package com.zsk.threadpool;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 自定义一个定长线程池
 * 
 * @author keke
 * @date 2020/05/12
 */
public class MyFixedThreadPool {
    // 线程集合
    private List<MyThead> threads;
    // 任务队列
    private ArrayBlockingQueue<Runnable> taskQueue;
    // 线程池初始大小
    private int threadNum;
    // 工作线程数目
    private int workThreadNum;
    // 锁
    private final ReentrantLock mainLock = new ReentrantLock();

    public MyFixedThreadPool(int poolNum) {
        workThreadNum = 0;
        threadNum = poolNum;
        threads = new ArrayList<>(poolNum);
        // 任务队列长度为线程池大小的10倍
        taskQueue = new ArrayBlockingQueue<>(poolNum * 10);

    }

    public void execute(Runnable runnable) {
        try {
            mainLock.lock();
            // 线程池未满,启动新线程执行
            if (workThreadNum < threadNum) {
                MyThead myThead = new MyThead(runnable);
                myThead.start();
                threads.add(myThead);
                workThreadNum++;
            } else {
                // 线程池已满,将任务加入待执行队列，等待有空闲线程时执行，否者拒绝任务
                if (!taskQueue.offer(runnable))
                    rejectTask();

            }
        } finally {
            mainLock.unlock();
        }
    }

    private void rejectTask() {
        System.out.println("任务队列已满，无法接受任务，请扩展线程池大小");
    }

    class MyThead extends Thread {

        private Runnable task;

        public MyThead(Runnable runnable) {
            this.task = runnable;
        }

        @Override
        public void run() {
            // 循环监控队列
            while (true) {
                try {
                    // 初始化时直接执行
                    if (task != null) {
                        task.run();
                        task = null;
                    } else {
                        // 阻塞任务
                        Runnable queueTask = taskQueue.take();
                        queueTask.run();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {

                }

            }
        }
    }

    public static void main(String[] args) {
        MyFixedThreadPool myThreadPool = new MyFixedThreadPool(5);
        Runnable task = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行中");
            }
        };

        for (int i = 0; i < 20; i++) {
            myThreadPool.execute(task);
        }
    }
}
